package pl.edu.pw.perg.compinfodb.datamodel;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

import pl.edu.pw.perg.compinfodb.entities.HistoryItem;
import pl.edu.pw.perg.compinfodb.entities.PhysicalElement;
import pl.edu.pw.perg.compinfodb.entities.VirtualElement;
import pl.edu.pw.perg.compinfodb.manager.IHistoryManager;

public class HistoryTableModel implements TableModel,
		IPhysicalElementSelectionListener {

	private static final String DESC = "Description";
	private static final String AUTHOR = "Author";
	private static final String DATE = "Date";
	private static final String[] COLS_NAMES = { DESC, AUTHOR, DATE };

	private IHistoryManager historyManager;
	private List<TableModelListener> listeners = new ArrayList<TableModelListener>();
	private List<IEventModificationListener> evtModificationListeners = new ArrayList<IEventModificationListener>();
	private String[] columnNames;
	private List<HistoryItem> history = new ArrayList<HistoryItem>();
	private PhysicalElement physicalElement;
	private List<HistoryItem> modified = new ArrayList<HistoryItem>();
	
	public HistoryTableModel(IHistoryManager historyManager) {
		this.historyManager = historyManager;
		columnNames = COLS_NAMES;
	}

	public void addTableModelListener(TableModelListener l) {
		listeners.add(l);
	}

	public Class<?> getColumnClass(int columnIndex) {
		return String.class;
	}

	public int getColumnCount() {
		return columnNames.length;
	}

	public String getColumnName(int columnIndex) {
		return columnNames[columnIndex];
	}

	public int getRowCount() {
		return history.size();
	}

	public Object getValueAt(int rowIndex, int columnIndex) {
		HistoryItem event = history.get(rowIndex);

		if (getColumnName(columnIndex).equals(DATE))
			return event.getCreationDate();
		if (getColumnName(columnIndex).equals(DESC))
			return event.getDescription();
		if (getColumnName(columnIndex).equals(AUTHOR))
			return event.getAuthor();
		throw new IllegalArgumentException("No such column!");
	}

	public boolean isCellEditable(int rowIndex, int columnIndex) {
		return history.get(rowIndex).getId() == null;
//		return true;
	}

	public void removeTableModelListener(TableModelListener l) {
		listeners.remove(l);
	}

	public void setValueAt(Object value, int rowIndex, int columnIndex) {
		HistoryItem event = history.get(rowIndex);
		if (getColumnName(columnIndex).equals(DESC))
			event.setDescription((String) value);
		else if (getColumnName(columnIndex).equals(AUTHOR))
			event.setAuthor((String) value);
		else
			throw new IllegalArgumentException("No such column!");
	}

	private void setVirtualElement(VirtualElement virtualElement) {
		history.clear();
		// history.addAll(historyManager.findElementHistory(virtualElement().getPE().getId()));
		// Map<Integer, Connector> connectorsPositions = new HashMap<Integer,
		// Connector>();
		//
		// for (Connector conn : connectors) {
		// connectorsPositions.put(input ? conn.getPositionIn() : conn
		// .getPositionOut(), conn);
		// }
		// int connsNumber = input ? virtualElement.getElementType()
		// .getInputConnectorsNr() : virtualElement.getElementType()
		// .getOutputConnectorsNr();
		// for (int i = 0; i < connsNumber; i++) {
		// // TODO: Jakos sensownie to zaimplementowac
		// // (dodanie pustych polaczen)
		// }
		// for (TableModelListener l : listeners) {
		// l.tableChanged(new TableModelEvent(this));
		// }
	}

	public void setHistoryManager(IHistoryManager historyManager) {
		this.historyManager = historyManager;
	}

	public void selectionChanged(PhysicalElement pe) {
		physicalElement = pe;
		history.clear();
		if(pe != null)
			history.addAll(historyManager.getElementHistory(pe.getId()));
		for (TableModelListener tml : listeners) {
			tml.tableChanged(new TableModelEvent(this));
		}
		historyChanged(false);
	}

	public void refresh(){
		history.clear();
		history.addAll(historyManager.refreshHistory(physicalElement.getId()));
		for (TableModelListener tml : listeners) {
			tml.tableChanged(new TableModelEvent(this));
		}
		historyChanged(false);

	}
	
	public void createEvent(){
		HistoryItem event = new HistoryItem();
		event.setPeId(physicalElement.getId());
		event.setCreationDate(new Date());
		history.add(event);
		for (TableModelListener tml : listeners) {
			tml.tableChanged(new TableModelEvent(this));
		}
		modified.add(event);
		historyChanged(true);
	}
	
	public void saveItems(){
		List<HistoryItem> toSave = new ArrayList<HistoryItem>();
		for (HistoryItem event : modified) {
			if(event.getAuthor() != null && event.getDescription() != null)
				toSave.add(event);
		}
		historyManager.saveAll(toSave);
		refresh();
		historyChanged(false);
	}

	public void addEventModifiactionListener(IEventModificationListener listener) {
		evtModificationListeners.add(listener);
	}
	
	public void historyChanged(boolean changed){
		for (IEventModificationListener l : evtModificationListeners) {
			l.historyChanged(changed);
		}
	}
}
